﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace WpfFlipit.Controls
{
    public class FlipClock : Control
    {
        private readonly DispatcherTimer _dispatcherTimer;

        private bool _isDisposed;

        #region NumberList
        public static readonly DependencyProperty NumberListProperty = DependencyProperty.Register(
            nameof(NumberList), typeof(List<int>), typeof(FlipClock), new PropertyMetadata(new List<int> { 0, 0, 0, 0, 0, 0 }));

        public List<int> NumberList
        {
            get => (List<int>)GetValue(NumberListProperty);
            set => SetValue(NumberListProperty, value);
        }
        #endregion

        #region DisplayTime
        public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register(
            nameof(DisplayTime), typeof(DateTime), typeof(FlipClock), new PropertyMetadata(default(DateTime), OnDisplayTimeChanged));

        private static void OnDisplayTimeChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
        {
            var ctl = (FlipClock)s;
            var v = (DateTime)e.NewValue;

            if (ctl.ShowSeconds)
            {
                ctl.NumberList = new List<int>
                {
                    ctl.Display24HrTime? v.Hour:(v.Hour%12),
                    v.Minute,
                    v.Second
                };
            }
            else
            {
                ctl.NumberList = new List<int>
                {
                    ctl.Display24HrTime? v.Hour:(v.Hour%12),
                    v.Minute
                };
            }

            if (!ctl.Display24HrTime)
            {
                ctl.TimeAbbr = v.Hour > 12 ? "PM" : "AM";
            }
        }

        public DateTime DisplayTime
        {
            get => (DateTime)GetValue(DisplayTimeProperty);
            set => SetValue(DisplayTimeProperty, value);
        }
        #endregion

        #region 24小时制


        public bool Display24HrTime
        {
            get { return (bool)GetValue(Display24HrTimeProperty); }
            set { SetValue(Display24HrTimeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Display24HrTime.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Display24HrTimeProperty =
            DependencyProperty.Register("Display24HrTime", typeof(bool), typeof(FlipClock), new PropertyMetadata(true));


        #endregion

        #region 显示秒


        public bool ShowSeconds
        {
            get { return (bool)GetValue(ShowSecondsProperty); }
            set { SetValue(ShowSecondsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowSeconds.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowSecondsProperty =
            DependencyProperty.Register("ShowSeconds", typeof(bool), typeof(FlipClock), new PropertyMetadata(true));


        #endregion

        #region 上午下午缩写


        public string TimeAbbr
        {
            get { return (string)GetValue(TimeAbbrProperty); }
            set { SetValue(TimeAbbrProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TimeAbbr.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TimeAbbrProperty =
            DependencyProperty.Register("TimeAbbr", typeof(string), typeof(FlipClock), new PropertyMetadata(string.Empty));


        #endregion

        public FlipClock()
        {
            _dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
            {
                Interval = TimeSpan.FromMilliseconds(200)
            };

            IsVisibleChanged += FlipClock_IsVisibleChanged;
        }

        ~FlipClock() => Dispose();

        public void Dispose()
        {
            if (_isDisposed) return;

            IsVisibleChanged -= FlipClock_IsVisibleChanged;
            _dispatcherTimer.Stop();
            _isDisposed = true;

            GC.SuppressFinalize(this);
        }

        private void FlipClock_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (IsVisible)
            {
                _dispatcherTimer.Tick += DispatcherTimer_Tick;
                _dispatcherTimer.Start();
            }
            else
            {
                _dispatcherTimer.Stop();
                _dispatcherTimer.Tick -= DispatcherTimer_Tick;
            }
        }

        private void DispatcherTimer_Tick(object sender, EventArgs e) => DisplayTime = DateTime.Now;
    }
}
